#include "lidarclient.h"
#include "../log/QsLog/QsLog.h"

#include <grpcpp/impl/codegen/async_unary_call.h>
#include <QThread>
#include <QSharedPointer>

LidarClient::LidarClient(std::shared_ptr<grpc::Channel> channel, QObject *parent)
    :QObject{parent}
    , m_stub(lidar::PMT::NewStub(channel))
    , m_cq()
{

}

LidarClient::~LidarClient()
{
    //m_stub = nullptr;
}

const QSharedPointer<lidar::RuntimeParamsPackage> LidarClient::getPMTState(const lidar::GUID request)
{
    unsigned int client_connection_timeout = 2000;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);

    //lidar::RuntimeParamsPackage* r = new lidar::RuntimeParamsPackage;
    const QSharedPointer<lidar::RuntimeParamsPackage> r(new lidar::RuntimeParamsPackage);
    grpc::Status status = m_stub->GetPMTState(&context, request, r.data());


    if (!status.ok()){
        qDebug()<< "GetPMTState rpc failed:"<<status.error_code()<<status.error_message();
        return nullptr;
    }
    qDebug() << " emit Sig_GetPMTState(r);";
    emit Sig_GetPMTState(r);

    return r;
}

const QSharedPointer<lidar::LaserStatus> LidarClient::getLaserStatus(const lidar::GUID request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);

    QSharedPointer<lidar::LaserStatus> r(new lidar::LaserStatus);
    grpc::Status status = m_stub->GetLaserStatus(&context, request, r.data());
    if (!status.ok()){
        qDebug()<< "GetLaserStatus rpc failed."<<status.error_code()<<status.error_message();
    }

    return r;
}

void LidarClient::setLaser(const lidar::LaserLD request)
{
    grpc::ClientContext context;
    ::google::protobuf::Empty r;
    grpc::Status status = m_stub->SetLaser(&context, request, &r);
    if (!status.ok()){
        qDebug()<< "SetLaser rpc failed.";
    }
}

void LidarClient::setRocMoveToAngle(const lidar::RocMovePara request)
{
    grpc::ClientContext context;
    ::google::protobuf::Empty r;
    grpc::Status status = m_stub->SetRocMoveToAngle(&context, request, &r);
    if (!status.ok()){
        qDebug()<< "SetRocMoveToAngle rpc failed.";
    }

}

const QSharedPointer<lidar::XError> LidarClient::startAcquire(const lidar::AcquireParamsPackage request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);

    QSharedPointer<lidar::XError> r(new lidar::XError);
    grpc::Status status = m_stub->StartAcquire(&context, request, r.data());
    if (!status.ok()){
        qDebug()<< "startAcquire rpc failed."<<status.error_code()<<status.error_message();
    }
    return r;
}

bool LidarClient::stopAcquire(const lidar::GUID request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);

    google::protobuf::Empty* r = new google::protobuf::Empty;
    grpc::Status status = m_stub->StopAcquire(&context, request, r);
    if (!status.ok()){
        qDebug()<< "stopAcquire rpc failed."<<status.error_code()<<status.error_message();
    }
}

const QSharedPointer<lidar::ComputedResult> LidarClient::getNextComputerData(const lidar::AlgrithmParamsPackage request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);


    QSharedPointer<lidar::ComputedResult> r(new lidar::ComputedResult);
    grpc::Status status = m_stub->GetNextComputeData(&context, request, r.data());
    if (!status.ok()){
        qDebug()<< "getNextComputerData rpc failed."<<status.error_code()<<status.error_message();
    }
    return r;
}

void LidarClient::compute(const lidar::ComputeParamsPackage request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);

    google::protobuf::Empty* r = new google::protobuf::Empty;
    grpc::Status status = m_stub->Compute(&context, request, r);
    if (!status.ok()){
        qDebug()<< "compute rpc failed."<<status.error_code()<<status.error_message();
    }

}

const QSharedPointer<lidar::LidarRawData> LidarClient::getNextData(const lidar::GUID request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);
    QSharedPointer<lidar::LidarRawData> r(new lidar::LidarRawData);
    grpc::Status status = m_stub->GetNextData(&context, request, r.data());
    if (!status.ok()){
        qDebug()<< "compute rpc failed."<<status.error_code()<<status.error_message();
    }
    return r;
}

void LidarClient::beginQueryData(const lidar::RawParamsPackage request)
{
    unsigned int client_connection_timeout = 500;

    grpc::ClientContext context;
    // Set timeout for API
    std::chrono::system_clock::time_point deadline =
        std::chrono::system_clock::now() + std::chrono::milliseconds(client_connection_timeout);
    context.set_deadline(deadline);
    google::protobuf::Empty* r = new google::protobuf::Empty;
    grpc::Status status = m_stub->BeginQueryData(&context, request, r);
    if (!status.ok()){
        qDebug()<< "compute rpc failed."<<status.error_code()<<status.error_message();
    }
}


void LidarClient::loopGetResponse()
{
    void* got_tag;
    bool ok = false;
    m_cq.Next(&got_tag, &ok);
    if(ok && got_tag == (void*)1){

    }
}
